Skip to content

Conversation

wanling0000
Copy link
Collaborator

@wanling0000 wanling0000 commented Jul 9, 2025

Closes #12350

Final PR based on draft: JabRef#714

This PR implements the logic-layer orchestration for Git push and pull operations with semantic merging support. It enables JabRef to semantically merge .bib files when possible, avoiding manual conflict resolution for simple changes.

This is part of ongoing work to support full Git-based collaboration for .bib files. Further tests and UI integration are planned.

Steps to test

This PR implements the first part of Git sync support by enabling automatic semantic merges when there are no conflicts. The scenario is tested via TDD in GitSyncServiceTest, simulating the following steps:

  • Alice creates an initial commit and pushes it to the remote.
  • Bob clones the repo and modifies entry b, then pushes.
  • Alice modifies entry a, then pulls.
    Since they changed different entries, we expect a clean merge without user intervention. The orchestrator is GitSyncService, and helper utilities and value objects are temporarily located in org.jabref.logic.git.util.

Documentation Supplement

🧩 Table: Git-related Class Responsibilities

Class Responsibility
GitSyncService Orchestrates Git operations (pull, merge, push). Handles conflict detection, semantic merging, and committing results.
GitHandler Wrapper around JGit, provides high-level Git operations like fetch, commit, push, and branch management.

🔧 Key Methods in GitSyncService

Method Purpose Description
fetchAndMerge(Path) Pulls and merges changes Runs status checks, fetch, 3-way merge, conflict detection, and auto-commit. Invokes a UI conflict resolution strategy if needed.
performSemanticMerge(...) Performs semantic 3-way merge Compares base/local/remote .bib content semantically. Uses SemanticMerger and conflict resolution strategy.
push(Path) Pushes local changes to remote Based on sync status, decides whether to commit and push. Fails if unresolved conflicts exist.

📦 Package: org.jabref.logic.git.io

This package bridges Git and JabRef's BibTeX data model by handling read/write operations for .bib files at specific Git revisions.

Class Responsibility
GitFileReader Reads raw .bib text from a specific Git commit.
GitFileWriter Writes BibDatabaseContext content back to a .bib file after merge.
GitRevisionLocator Locates base, local, and remote commits for 3-way merge.
RevisionTriple Data structure that holds the result of locating base, local, and remote revisions.

📦 Package: org.jabref.logic.git.status

Handles detection of Git repository and file tracking/sync status. Used before pull/push to determine the correct operation.

Class Responsibility
GitStatusChecker Static utility to check Git status of a .bib file and return a snapshot.
GitStatusSnapshot Immutable snapshot of a file's Git tracking/conflict/sync state.
SyncStatus Enum representing sync state (e.g., UP_TO_DATE, BEHIND, DIVERGED, etc.).

📦 Package: org.jabref.logic.git.conflicts

Handles semantic conflict detection and resolution strategies during 3-way merge.

Class Responsibility
SemanticConflictDetector Detects entry-level conflicts between base/local/remote BibDatabaseContexts.
ThreeWayEntryConflict Data structure representing a single entry-level 3-way conflict.
GitConflictResolverStrategy Interface for resolving conflicts — supports GUI/CLI strategies.
CliConflictResolverStrategy CLI implementation (planned for JabKit, not yet integrated). GUI is currently prioritized.

Conflict Resolution Flow:

  1. Detect conflicts with SemanticConflictDetector.

  2. If conflicts exist, invoke a GitConflictResolverStrategy:

    • In GUI: use GuiConflictResolverStrategy

    • In future CLI: use CliConflictResolverStrategy

  3. Apply merge plan if resolution succeeds.


📦 Package: org.jabref.logic.git.merge

Executes semantic 3-way merge operations on .bib files, including building merge plans and applying field-level changes.

Class Responsibility
MergePlan Represents semantic changes from base → remote to be applied to local.
SemanticMerger Applies a MergePlan to a local BibDatabaseContext.
GitSemanticMergeExecutor Interface defining a performSemanticMerge() contract.
GitSemanticMergeExecutorImpl Default implementation of the above; invokes detector and merger.
GitMergeUtil Utility class for low-level field and entry merging.

💡 GUI Module Integration Note

  • GUI dependencies are temporarily introduced to reuse the existing MergeEntriesDialog for conflict resolution.

  • This is injected via GitConflictResolverStrategy to keep the dependency direction correct (logic → gui).

  • A major UI refactor is WIP.

Class Responsibility
GuiConflictResolverStrategy GUI-based conflict resolution strategy. Reuses MergeEntriesDialog to let users manually resolve semantic conflicts in BibEntrys.

Mandatory checks

  • I own the copyright of the code submitted and I license it under the MIT license
  • [/] Change in CHANGELOG.md described in a way that is understandable for the average user (if change is visible to the user)
  • Tests created for changes (if applicable)
  • Manually tested changed features in running JabRef (always required)
  • [/] Screenshots added in PR description (if change is visible to the user)
  • Checked developer's documentation: Is the information available and up to date? If not, I outlined it in this pull request.
  • Checked documentation: Is the information available and up to date? If not, I created an issue at https://github.com/JabRef/user-documentation/issues or, even better, I submitted a pull request to the documentation repository.

@wanling0000 wanling0000 force-pushed the clean-gsoc-git-support-init branch from 8302ebc to 32c30a0 Compare July 14, 2025 00:54
@wanling0000
Copy link
Collaborator Author

wanling0000 commented Jul 30, 2025

In org.jabref.logic.git.conflicts, we need a package-info.java explaining the whole idea maybe :)

We need a test when this removes/ignores/... entries, because they don't have a cition key.

@article{,
  author = {test}
}

If possible, more tests should be added

case 3 in org.jabref.logic.git.conflicts.SemanticConflictDetector#detectConflicts seems to be untested (maybe related to my Windows machine and issues with non-closed git object)

image

Thanks, this comment really helped me realize a flaw in the current logic... 🥲

Right now, conflict detection relies entirely on citation key matching and only performs field-level comparison. Entry-level changes (like additions, deletions, or key changes) are only inferred indirectly via BibEntryDiff (e.g., via nulls), which risks missing edge cases.

I can fix this logic in the current PR by performing an explicit entry-level three-way comparison before checking for field-level conflicts. It might require an extra review of the updated SemanticConflictDetector and the test matrix.

Alternatively, I'm happy to keep this PR as is and address the logic fix in a separate PR right after this gets merged

Let me know what you prefer!

@InAnYan
Copy link
Member

InAnYan commented Jul 30, 2025

I think we with Oliver would really like to see this PR merged. So I think you can write new features in the follow up PR 😋

@koppor
Copy link
Member

koppor commented Jul 31, 2025

Regarding the algorithm: Maybe "just" using https://github.com/JabRef/jabref/blob/main/jablib/src/main/java/org/jabref/logic/bibtex/comparator/BibDatabaseDiff.java solves issues?

Merging this stats can later help to compare different approaches. Having the approaches here in the PR "hides" them between other discussions.

@wanling0000
Copy link
Collaborator Author

Regarding the algorithm: Maybe "just" using https://github.com/JabRef/jabref/blob/main/jablib/src/main/java/org/jabref/logic/bibtex/comparator/BibDatabaseDiff.java solves issues?

Merging this stats can later help to compare different approaches. Having the approaches here in the PR "hides" them between other discussions.

Thank you! I’m currently using BibDatabaseDiff in SemanticConflictDetector to get remoteDiffs. But I now realize that to handle edge cases (e.g. entries without citation keys, or ones only changed in local), I also need to compute localDiffs.

Only relying on remoteDiffs plus the local map isn’t enough, because it would miss entries that are added or changed only in local.

I’ll revise the logic in the follow-up PR

Copy link

trag-bot bot commented Aug 1, 2025

@trag-bot didn't find any issues in the code! ✅✨

@koppor
Copy link
Member

koppor commented Aug 1, 2025

Retested on windows - added some fixes because of eclipse-jgit/jgit#155 (comment)

@subhramit
Copy link
Member

subhramit commented Aug 1, 2025

Retested on windows - added some fixes because of eclipse-jgit/jgit#155 (comment)

I think you forgot to push?
Clarified over text - incoming follow-up. Will get this merged now.

@subhramit subhramit added this pull request to the merge queue Aug 1, 2025
Merged via the queue into JabRef:main with commit bfa37f0 Aug 1, 2025
1 check passed
@JabRef JabRef deleted a comment from trag-bot bot Aug 1, 2025
@JabRef JabRef deleted a comment from trag-bot bot Aug 1, 2025
Siedlerchr added a commit that referenced this pull request Aug 2, 2025
* upstream/main:
  Issue 13619 Make Citation relations text more clear. (#13620)
  Explain how to handle notifications (#13630)
  Fix scope of 'determine issue number' job (#13627)
  Add proper closing (#13626)
  Implement logic orchestration for Git Pull/Push operations (#13518)
  Make pattern for issue number more strict
  Fix "Cannot load file MultiMergeEntries.fxml" (#13624)
  Add Copy markdown to copy citation (#13387)
  Add ADR-0047 (#13621)
  Initial start of implementing a LSP for integrity checks (#13612)
  Refactor merge entries package structure (#13614)
  New Crowdin updates (#13616)
  BibEntry class no longer implements Cloneable (#13615)
  Fix dark mode in {} of Citation Relations tab of the entry editor (#13609)
  Update dependency org.kohsuke:github-api to v2.0-rc.4 (#13611)
  Fix setting of proxy without password (#13605)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Add (simple) git support
4 participants